using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Collections;
using System.Linq.Expressions;
using Q.Framework.Utility;
using Q.Framework.Extension;
using System.Data.Objects;

namespace Q.Framework.WebControls
{
    public class QDropDownList : DropDownList, IBindableControl
    {
        public string DataPropertyName { get; set; }

        private String controlBindableProperty = "SelectedValue";
        public string ControlBindableProperty
        {
            get { return controlBindableProperty; }
            set { controlBindableProperty = value; }
        }

        /// <summary>
        /// Mensagem de Validação
        /// </summary>
        public String ValidationMessage { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="QDropDownList"/> is required.
        /// </summary>
        /// <value>
        ///   <c>true</c> if required; otherwise, <c>false</c>.
        /// </value>
        public Boolean Required { get; set; }

        private RequiredFieldValidator _required;

        private void CreateRequiredFieldValidator()
        {
            if (this.Required)
            {
                _required = new RequiredFieldValidator();
                _required.ControlToValidate = this.ID;
                _required.ErrorMessage = String.Empty;
                _required.Text = String.Format(" {0}", ValidationMessage == null ? "*" : ValidationMessage);
                _required.ToolTip = ValidationMessage == null ? "Campo Obrigatório" : String.Empty;
                _required.Display = ValidatorDisplay.Dynamic;
                _required.ForeColor = System.Drawing.Color.Red;
                _required.ValidationGroup = "validationGroup";

                Controls.Add(_required);

                this.Style.Add("border-left", "4px solid #B22222");
            }
        }

        public override void Focus()
        {
            JavaScriptAdd.SetFocus(this.Page, this.ClientID);
        }

        private void CreateSummary()
        {
            if (this.Required)
            {
                // contador de verificação dos controles CustomTextBox
                Int16 count = 0;
                // percorre todos os controles da página
                foreach (Control _control in Page.Form.Controls)
                {
                    // se controle for do tipo da classe 
                    // personalizada que estamos desenvolvendo
                    if (_control.GetType() == typeof(QDropDownList))
                    {
                        // se o objeto está sendo acessado pela 
                        // primeira vez
                        if (count == 0)
                            // se o controle encontrado é o controle que
                            // provocou a chamada
                            if (_control.ID == this.ID)
                            {
                                // cria Summary e fixa propriedades
                                ValidationSummary _summary = new ValidationSummary();
                                // ** sugestão: preencha esta propriedade
                                // para mensagem comuns
                                //_summary.HeaderText = "Verifique os 
                                // campos Obrigatórios.";
                                _summary.ShowMessageBox = true;
                                _summary.ShowSummary = false;
                                _summary.ID = "vsTextBox";
                                _summary.DisplayMode = ValidationSummaryDisplayMode.List;
                                _summary.ValidationGroup = "validationGroup";
                                // adiciona controles
                                Controls.Add(_summary);
                            }
                        // incrementa à quantidade de controles do 
                        // tipo CustomTextBox encontrados
                        count++;
                    }
                }
            }
        }

        /// <summary>
        /// Handles the <see cref="E:System.Web.UI.Control.Init"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            if (!this.DesignMode)
            {
                CreateRequiredFieldValidator();
            }
        }

        /// <summary>
        /// Renders the specified w.
        /// </summary>
        /// <param name="w">The w.</param>
        protected override void Render(HtmlTextWriter w)
        {
            base.Render(w);

            if (!this.DesignMode)
            {
                if (this.Required)
                    _required.RenderControl(w);

                CreateSummary();
            }

        }

        /// <summary>
        /// Limpa os Itens e o Valor Selecionado
        /// </summary>
        public void Clear()
        {
            this.Items.Clear();
            this.SelectedValue = null;
        }


        /// <summary>
        /// Preenche o controle com um enumerado
        /// </summary>
        /// <typeparam name="T">Tipo do Enumerado</typeparam>
        public void FillWithEnum<T>()
        {
            ArrayList lista = new ArrayList();

            foreach (Enum enumValue in Enum.GetValues(typeof(T)))
            {
                if (enumValue.ToString().ToUpper() == "NONE" || enumValue.ToString().ToUpper() == "NAODEFINIDO")
                    continue;

                var outraClasseAnonima = new { Codigo = enumValue.GetValue(), Descricao = enumValue.GetDescription() };

                lista.Add(outraClasseAnonima);
            }

            this.DataValueField = "Codigo";
            this.DataTextField = "Descricao";
            this.DataSource = lista;
            this.DataBind();
            this.Items.Insert(0, new ListItem("-- Selecione --", String.Empty));

        }

        /// <summary>
        /// Obtém o valor Selecionado quando o controle foi preenchido com um enumerado
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetSelectedFilledWithEnum<T>() where T : struct, IConvertible
        {
            if (this.SelectedValue == null)
                throw new ValidationException("Nenhum valor selecionado");

            return EnumExtension.GetEnum<T>(this.SelectedValue);
        }

        /// <summary>
        /// Obtém o ID Selecionado
        /// </summary>
        /// <returns></returns>
        public Int32? GetID()
        {

            if (!this.Required && this.SelectedValue == null || String.IsNullOrWhiteSpace(this.SelectedValue))
                return null;

            if (this.SelectedValue == null || String.IsNullOrWhiteSpace(this.SelectedValue))
                throw new ValidationException("Nenhum valor selecionado");

            return Convert.ToInt32(this.SelectedValue);

        }

        /// <summary>
        /// Obtém o valor Selecionado
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="C"></typeparam>
        /// <returns></returns>
        public T GetSelected<T>()
        {
            if (!this.Required && this.SelectedValue == null || String.IsNullOrWhiteSpace(this.SelectedValue))
                return Activator.CreateInstance<T>();

            if (this.SelectedValue == null || String.IsNullOrWhiteSpace(this.SelectedValue))
                throw new ValidationException("Nenhum valor selecionado");

            var x = Data.DAOGeneric.GetById<T>(Convert.ToInt32(this.SelectedValue));

            if (x == null)
                x = Activator.CreateInstance<T>();

            return x;
        }

        /// <summary>
        /// Creates a collection to store child controls.
        /// </summary>
        /// <returns>
        /// Always returns an <see cref="T:System.Web.UI.EmptyControlCollection"/>.
        /// </returns>
        protected override ControlCollection CreateControlCollection()
        {
            return new ControlCollection(this);
        }

        /// <summary>
        /// Preenche o Controle com dados do BD
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="C"></typeparam>
        /// <param name="dataValueField">Nome da Propriedade valor</param>
        /// <param name="dataTextField">Nome da Propriedade de exibição</param>
        /// <param name="exibirSelecionar">Indica se será incluido um valor "Selecionar"</param>
        public void Fill<T>(String dataValueField = "ID", String dataTextField = "Descricao", Boolean exibirSelecionar = true)
        {
            this.DataValueField = dataValueField;
            this.DataTextField = dataTextField;
            this.DataSource = Data.DAOGeneric.SelectAll<T>();
            this.DataBind();

            if (exibirSelecionar)
                this.Items.Insert(0, new ListItem("-- Selecione --", String.Empty));
        }
        
        /// <summary>
        /// Preenche o Controle com dados do BD que satisfazem uma determinada condição
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="C"></typeparam>
        /// <param name="where">Condição de Filtragem</param>
        /// <param name="dataValueField">Nome da Propriedade valor</param>
        /// <param name="dataTextField">Nome da Propriedade de exibição</param>
        /// <param name="exibirSelecionar">Indica se será incluido um valor "Selecionar"</param>
        public void Fill<T>(Expression<Func<T, bool>> where, String dataValueField = "ID", String dataTextField = "Descricao", Boolean exibirSelecionar = true)
        {
            this.DataValueField = dataValueField;
            this.DataTextField = dataTextField;
            this.DataSource = Data.DAOGeneric.SelectWhere<T>(where);
            this.DataBind();
            if (exibirSelecionar)
                this.Items.Insert(0, new ListItem("-- Selecione --", String.Empty));
        }

        /// <summary>
        /// Altera o valor Selecionado de acordo com um objeto
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        public void SetValue<T>(T value) where T : class
        {
            SelectedValue = typeof(T).GetProperty(DataValueField).GetValue(value, null).ToString();
        }

        /// <summary>
        /// Altera o valor Selecionado de acordo com um Enumerado
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        public void SetEnumValue<T>(T value) where T: struct
        {
            SelectedValue = Q.Framework.Extension.EnumExtension.GetValue(value as Enum);
        }
    }
}